package client;

import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.ArrayList;

import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.FontUIResource;

public class MyJFrame extends JFrame {

	// 窗体大小
	private final int WIDTH = 810;
	private final int HEIGHT = 640;

	Date d; // 获取的容器时间
	
	// 需要修改或访问的组件
	private JButton openFileButton; // 打开文件按钮
	private JButton lunchButton; // 发送消息按钮
	private JTextArea editArea; // 文本框
	private JTextArea messageArea; // 消息显示区域
	DefaultListModel<Friend> model; // 朋友模型数据

	// 信息处理类
	private Client myClient;
	private Friend slectedFriend = null; // 选中的朋友
	private ArrayList<Friend> myFriends; // 在线朋友列表
	File path = null; // 选中的文件路径

	// 获取文件流的容器
	boolean getInputStream = false; // 标记是否已经获取过inputStream
	FileInputStream inputStream = null; // 文件传输流

	// 构造函数：布局构造、开启发送和监听线程
	public MyJFrame(Client client) throws UnknownHostException {

		// 创建框架、初始设置
		super("Commo");
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		// 添加关闭窗口监听者：关闭窗口保存文件
		this.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				loadMessage();
				System.exit(0);
			}

		});
		this.setSize(WIDTH, HEIGHT); // 窗体大小
		this.setResizable(false); // 大小不可修改

		Container container = this.getContentPane(); // 获取容器
		container.setBounds(0, 0, 800, 600); // 容器大小
		container.setLayout(null); // 无布局

		// 添加组件
		container.add(initLeftPanel()); // 初始化左侧联系人列表
		container.add(initUpPanel()); // 初始化消息显示列表
		container.add(initDownPanel()); // 初始化下方文本输入区域

		this.myClient = client; // 初始化Client
		myClient.start(); // 开始交互线程 发送消息功能就绪

		this.setVisible(true); // 可视(放在最后设置以显示所有组件)

		// 开始监听消息线程
		new Thread(new Runnable() {
			@Override
			public void run() {
				acceptMessage();
			}
		}).start();
	}


	// 监听线程: 循环收取信息方法
	private void acceptMessage() {
		try (InputStream input = this.myClient.getSocket().getInputStream()) {
			System.out.println("收消息功能就绪");
			BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8));
			// 循环监听
//			String
			while (true) {
				String tmpString = read(reader); // 获取信息

				Date d = Date();
				System.out.println("你收到消息 " + tmpString);
				// 获取到消息进行解析
				switch (tmpString.charAt(0)) {

				// 服务器
				case 'a':
					// 解析
					System.out.println("服务器发来消息 当前人数" + myFriends.size());

					Friend tmpFriend = findFriend("fuwuqi"); // 服务器
					tmpFriend.setMessage(tmpFriend.getMessage() + "\r\n" +tmpString.substring(1)); // 在原有消息基础上添加更新消息,注意删去指令
					if (slectedFriend == tmpFriend) // 如果当前页面就是服务器
					{
//						System.out.println(slectedFriend.toString()+"消息收到且显示为"+slectedFriend.getMessage());
						updateMessage(); // 直接更新显示
					}
					break;

				// 群聊
				case 'b':
					System.out.println("群聊收到消息");
					Friend tmpFriend1 = findFriend("qunliao"); // 使用指定名称锁定群聊
					tmpFriend1.setMessage(tmpFriend1.getMessage() + "\r\n" + tmpString.substring(1)); // 在原有消息基础上添加更新消息,删去指令
					if (slectedFriend.getAddress().toString().equals(tmpFriend1.getAddress())) // 如果当前页面就是群聊
						updateMessage(); // 直接更新显示
					break;

				// 个人
				case 'c':
					int length = InetAddress.getLocalHost().toString().length(); // 获取地址的长度
					String fromAddress = tmpString.substring(1, length + 1); // 地址信息
					System.out.println(fromAddress + " 给你发了一条消息");
					Friend tmpFriend2 = findFriend(fromAddress); // 使用指定地址锁定朋友
					tmpFriend2.setMessage(
							tmpFriend2.getMessage() + "\r\n" +  fromAddress + "说" + tmpString.substring(length + 1)); // 在原有消息基础上添加更新消息,删去指令、地址转换为名称
					if (slectedFriend.getAddress().toString().equals(tmpFriend2.getAddress())) // 如果当前页面就是群聊
						updateMessage(); // 直接更新显示
					break;

				// 用户信息更新
				case 'd':
					System.out.println("更新朋友圈");
					String address = tmpString.substring(1); // 获取地址
					// 更新地址
					addFriend(address);

					// 接收文件
				case 'e':
					System.out.println("接收文件");
					int length1 = InetAddress.getLocalHost().toString().length();
					String fromAddress1 = tmpString.substring(1, length1 + 1); // 获取文件传输地址
//					long length2 = Long.parseLong(tmpString.substring(length1+1)); // 获取文件大小
					Friend tmpFriend3 = findFriend(fromAddress1); // 找到发文件的好友
					tmpFriend3.setMessage(tmpFriend3.getMessage() + "\r\n" + fromAddress1 + "传输文件给你，请在 D:\\查收");
					if (slectedFriend.getAddress().equals(tmpFriend3.getAddress()))
						updateMessage(); // 直接更新

					// 紧接着读取传过来的文件
					if (!getInputStream) {
						inputStream = (FileInputStream) input; // 传入的文件流
						getInputStream = true;
					}

					// 在D盘创建新文件以接受文件
					File file = new File("D:\\");
					file.createNewFile();
					FileOutputStream outputStream = new FileOutputStream(file); // 获取
					byte[] p = new byte[1024];
					int n;

					// 目前只支持小于1024字节的文件 大于的话一次传输不完
					while ((n = inputStream.read(p)) != -1) {
						outputStream.write(p);
						; // 把p写到文件file
					}
					outputStream.flush(); // 刷新一下
				default:
					break;
				}
			}

		} catch (Exception e) {
		}
	}

	
	// 内部使用的小方法
	
	// 找到指定地址字符串的朋友
	private Friend findFriend(String s) {
		for (var fri : myFriends) {
			if (s.equals(fri.getAddress()))
				return fri;
		}
		System.out.println("没找到该联系人");
		return null;
	}
	
	// 获取时间
	private Date Date() {
		// TODO Auto-generated method stub
		return null;
	}

	// 添加新上线的朋友
	private void addFriend(String address) {
		Friend f = new Friend(address, address); // 新建朋友
		myFriends.add(f); // 加入朋友圈
		model.addElement(f); // 加入视图
	}

	// 读方法：传入BufferedRewder，返回String
	private String read(BufferedReader reader) throws IOException {

		// 直接读取全部信息
		char[] tmp = new char[1024];
		reader.read(tmp);
		int length = 0; // 存储字符长度
		for (int i = 0; i < 1024; i++) {
			if (tmp[i] == 0) {
				length = i;
				break;
			}
		}
		return new String(tmp).substring(0, length);

	}

	// 传入String的发消息方法
	private void sendMessage(String message) {
		myClient.sendMessage(message);
	}

	// 我自己发的消息显示到聊天区域
	private void showMyMessage(String s) {
		d = new Date();
		slectedFriend.setMessage(slectedFriend.getMessage() + "\r\n我说：["+d.toString()+"]" + s);// 对该朋友换行更新消息
		messageArea.setText(slectedFriend.getMessage()); // 更新messageArea
	}

	// 更新选中朋友的信息
	private void updateMessage() {
		messageArea.setText(slectedFriend.getMessage());
	}

	// 将朋友的message保存到本地
	private void loadMessage() {
		// 找到或者创建文件
		File f = new File("D:\\message.dat");
		if(!f.isFile())
			try {
				f.createNewFile();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		try {
			FileWriter writer = new FileWriter(f,StandardCharsets.UTF_8,true);
			for(var friend : myFriends) {
				writer.write(friend.toString()+"：");
				writer.write(friend.getMessage());
				writer.write("\r\n");
		}
			writer.write("\r\n\r\n");
			writer.close();
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	
	
	// 初始化监听者
	
	// 选中要发送消息的用户时的动作
	private void listenContactsList(JList list) {
		// 监听联系人列表
		list.addListSelectionListener(new ListSelectionListener() {
			@Override
			public void valueChanged(ListSelectionEvent e) {
				// 相关组件修改为可操作
				editArea.setEditable(true); // 可编辑
				openFileButton.setEnabled(true); // 可打开文件
				lunchButton.setEnabled(true); // 可发送
				// 相关组件对象修改

				Friend index = findFriend(((Friend) list.getSelectedValue()).getAddress()); // 找到选中的用户
				System.out.println("选中了" + index.toString()); // toString方法返回朋友姓名
				slectedFriend = index; // 更新选中的朋友
				messageArea.setText(slectedFriend.getMessage()); // 更新消息栏数据为与该朋友的聊天记录

			}
		});
	}

	// 打开历史记录文件
	private void openMessageFile(JButton button) {
		button.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				// TODO Auto-generated method stub
				File file=new File("D:\\message.dat");
				try {
					java.awt.Desktop.getDesktop().open(file);
				} catch (IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
			
		});
	}
	
	// 发消息
	private void lunchMessage(JButton button) {
		// 发送按钮的事件监听者
		button.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {

				// 如果编辑区有文字，显示文本并发送
				String tmpString = editArea.getText();
				if (tmpString.length() > 0) {
					System.out.println("显示了消息" + tmpString);
					showMyMessage(tmpString); // 在本地文本区显示自己发的消息
					// 依情况编码
					switch (slectedFriend.getAddress().charAt(0)) {

					case 'f': // 服务器
						sendMessage("a" + tmpString);
						break;

					case 'q': // 群聊
						sendMessage("b" + tmpString);
						break;

					default:
						sendMessage("c" + slectedFriend.getAddress() + tmpString); // 编码+地址+消息
						break;
					}
					editArea.setText(""); // 输入框清零
				}

			}
		});
	}

	// 打开文件
	private void openFile(JButton button) {
		button.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				JFileChooser jfc = new JFileChooser();
				jfc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
				jfc.showDialog(new JLabel(), "选择");
				File file = jfc.getSelectedFile();
				path = file.getAbsoluteFile(); // 获取绝对路径
				try {
					myClient.sendFile(path, slectedFriend.getAddress(), path.length()); // 文件路径、传输地址、大小
				} catch (InterruptedException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				} // 传输文件
			}

		});
	}

	
	// 图形界面初始化方法

	// 左侧联系人初始化、添加基本myFriends(服务器、群聊)
	private JComponent initLeftPanel() throws UnknownHostException {

		// TODO 此处inetAddress需修改
		JList<Friend> contactsList = new JList<>(); // 联系人列表
		listenContactsList(contactsList); // 监听联系人列表
		contactsList.setFixedCellHeight(40); // 行高
		contactsList.setFont(new Font("楷体", Font.BOLD, 20)); // 字体
		contactsList.setBackground(new Color(139, 126, 102)); // 列表背景色
		contactsList.setForeground(new Color(238, 213, 210)); // 列表字体颜色

		DefaultListCellRenderer listCellRenderer = new DefaultListCellRenderer();
		listCellRenderer.setHorizontalAlignment(SwingConstants.CENTER); // 居中对齐
		contactsList.setCellRenderer(listCellRenderer);

		JScrollPane leftPanel = new JScrollPane(contactsList); // 添加滚动条
		leftPanel.setBounds(0, 0, 150, 600); // 设置位置、面积

		// 设置列表数据
		model = new DefaultListModel<>(); // 数据模型
		model.addElement(new Friend("服务器", "fuwuqi")); // 添加本地地址
		model.addElement(new Friend("世界", "qunliao"));

		myFriends = new ArrayList<>();
		myFriends.add(new Friend("服务器", "fuwuqi")); // 初始化朋友列表
		myFriends.add(new Friend("群聊", "qunliao"));

		contactsList.setModel(model); // 添加到列表

		return leftPanel;
	}

	// 消息显示区域初始化
	private JComponent initUpPanel() {

		messageArea = new JTextArea(); // 消息区域
		messageArea.setEditable(false);
		messageArea.setForeground(new Color(112, 128, 144)); // 字体颜色
		messageArea.setFont(new Font("楷体", FontUIResource.BOLD, 20));

		messageArea.setBackground(new Color(240, 255, 240)); // 背景色
		JScrollPane upPanel = new JScrollPane(messageArea); // 滚动面板
		upPanel.setBounds(150, 0, 650, 400); // 面积

		return upPanel;
	}

	// 文本输入区域初始化
	private JComponent initDownPanel() {

		JPanel downPanel = new JPanel(null); // 新建面板，无布局
		downPanel.setBounds(150, 400, 650, 200); // 设置区域
		downPanel.setForeground(ColorUIResource.black);
		downPanel.setBackground(ColorUIResource.red); // 背景色

		editArea = new JTextArea("Input something"); // 文本输入区域
		editArea.setEditable(false); // 未选中对象初始不可写
		editArea.setLineWrap(true); // 自动换行
		editArea.setForeground(ColorUIResource.black); // 黑色字体
		editArea.setBackground(ColorUIResource.white); // 背景色
		editArea.setFont(new Font("楷体", Font.BOLD, 20)); // 字体设置
		JScrollPane editPane = new JScrollPane(editArea); // 添加滚动轴
		editPane.setBounds(0, 0, 500, 200);// 位置
		downPanel.add(editPane); // 文本框添加到面板
		
		JButton openMessageButton = new JButton("历史");
		openMessageFile(openMessageButton); // 打开历史文件监听者
		openMessageButton.setMargin(new Insets(0, 0, 0, 0));
		openMessageButton.setBounds(540, 0, 50, 30);
		downPanel.add(openMessageButton);
		

		openFileButton = new JButton("打开");
		openFileButton.setEnabled(false); // 初始不可按
		openFile(openFileButton);
		openFileButton.setMargin(new Insets(0, 0, 0, 0));
		openFileButton.setBounds(540, 50, 50, 30);
		downPanel.add(openFileButton);

		lunchButton = new JButton("发送");
		lunchButton.setEnabled(false); // 初始不可按
		lunchMessage(lunchButton);
		lunchButton.setMargin(new Insets(0, 0, 0, 0)); // 边距设0
		lunchButton.setBounds(540, 120, 50, 30); // 位置
		downPanel.add(lunchButton); // 发送按钮添加到panel

		return downPanel;
	}

}
